package com.ztools.pc.component;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.ztools.common.model.pc.bo.common.WebSocketBo;
import com.ztools.common.model.pc.sys.User;
import com.ztools.common.util.common.TokenUtil;
import com.ztools.pc.service.sys.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author:seeTools
 * @Date: 2023/4/1  15:54
 * @Version 1.0
 */
@Slf4j
@Component
@ServerEndpoint("/webSocket/{token}")
public class WebSocketServer {

    /**
     * 记住当前在线连接数
     */
    public static final Map<String, Session> SESSION_MAP = new HashMap<String, Session>();
    private static TokenUtil tokenUtil;
    private static UserService userService;

    @Autowired
    public void setChatService(UserService userService) {
        WebSocketServer.userService = userService;
    }

    @Autowired
    public void setChatService(TokenUtil tokenUtil) {
        WebSocketServer.tokenUtil = tokenUtil;
    }


    /**
     * 连接建立成功的方法
     *
     * @param session session
     * @param token   token
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("token") String token) {
        User user = userService.findUserByToken(token);
        SESSION_MAP.put(user.getId() + "", session);
        onlineNotice(user);
        log.info("开启连接:连接人员为:{}", user.getShowName());
    }


    @OnClose
    public void onClone(Session session, @PathParam("token") String token) {
        User user = userService.findUserByToken(token);
        SESSION_MAP.remove(user.getId() + "");
        log.info("连接关闭，移除用户{}的session，当前在线人数为：{}", user.getShowName(), SESSION_MAP.size());
    }

    /**
     * 收到客户端的消息
     *
     * @param message 客户端发来的消息
     * @param session session
     * @param token   token
     */
    @OnMessage
    public void onMessage(String message, Session session, @PathParam("token") String token) {
        User user = userService.findUserByToken(token);
        WebSocketBo webSocketData = JSONUtil.toBean(message, WebSocketBo.class);
        if ("heartBeat".equals(webSocketData.getType())) {
            // 心跳响应
            WebSocketBo webMessage = WebSocketBo.builder().type("heartBeat").message("朕知道了").build();
            onlineNotice(user);
            sendMessage(JSONUtil.toJsonStr(webMessage), session);
        } else if ("chat".equals(webSocketData.getType())) {
            // 聊天场景
            User toUser = userService.getById(webSocketData.getToUserId());
            webSocketData.setUser(user);
            WebSocketBo fromWebData = ObjectUtil.clone(webSocketData);
            fromWebData.setUser(toUser);
            Session fromSession = SESSION_MAP.get(webSocketData.getFromUserId() + "");
            Session toSession = SESSION_MAP.get(webSocketData.getToUserId() + "");
            sendMessage(JSONUtil.toJsonStr(fromWebData), fromSession);
            sendMessage(JSONUtil.toJsonStr(webSocketData), toSession);
            log.info("用户{}给用户{}发消息，消息内容为：{}", webSocketData.getFromUserId(), webSocketData.getToUserId(), webSocketData.getMessage());
        }
    }

    /**
     * 发生错误时执行的方法
     *
     * @param session session
     * @param error   error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("发送错误");
        error.printStackTrace();
    }

    /**
     * 服务端给客户端发送消息
     *
     * @param message message
     * @param session session
     */
    public void sendMessage(String message, Session session) {
        try {
            log.info("服务端给{}客户端发送消息{}", session.getId(), message);
            session.getBasicRemote().sendText(message);
        } catch (Exception e) {
            log.error("服务端发消息给客户端失败", e);
        }
    }

    /**
     * 服务器给所有客户端发消息
     *
     * @param message message
     */
    public void sendAllMessage(String message) {
        try {
            for (Session session : SESSION_MAP.values()) {
                log.info("服务端{}给客户端{}发送消息", session.getId(), message);
                session.getBasicRemote().sendText(message);
            }
        } catch (Exception e) {
            log.error("服务器给客户端发送消息失败", e);
        }
    }

    /**
     * 上线通知
     *
     * @param user user
     */
    public void onlineNotice(User user) {
        WebSocketBo online = WebSocketBo.builder()
                .type("online")
                .fromUserId(user.getId())
                .user(user)
                .build();
        sendAllMessage(JSONUtil.toJsonStr(online));
    }

}
